// Capitalist City - Business Simulation Game
// Copyright (C) 2011 Azlan Mukhtar
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
#include <QMessageBox>
#include "productsimulation.h"
#include "citysimulation.h"
#include "helper.h"
#include "game.h"

ProductSimulation::ProductSimulation() : isItemDatabaseLoaded(false), m_productIdCounter(0)
{

    if (ParseItemsFromFile())
    {
        isItemDatabaseLoaded = true;
        qDebug() << "Load item database OK";
    }
}


ProductSimulation::ProductSimulation(quint32 a_productIdCounter)
{
    m_productIdCounter = a_productIdCounter;
    ParseItemsFromFile();
}

ProductSimulation::~ProductSimulation()
{
    foreach(Product* i, m_productMap)
    {
        quint16 key = i->productType;
        delete i;
        m_productMap.remove(key, i);
    }

}

void ProductSimulation::AddProduct(quint16 a_productType,
                                      quint8  a_quality,
                                      quint8  a_brandLoyalty,
                                      quint8  a_brandAwareness,
                                      quint64 a_sellPrice,
                                      quint8  a_rating,
                                      quint8  a_cityAverageRating,
                                      quint64 a_purchasePrice,
                                      quint64 a_freightCost,
                                      quint64 a_totalCost,
                                      quint8  a_marketShare,
                                      quint8  a_productDemand,
                                      quint32 a_productId)
{
    m_product = new Product;

    if (a_productId != 0)
    {
        m_product->productId = a_productId;
    } 
    else
    {
        m_product->productId = m_productIdCounter;
    }

    m_product->productType = a_productType;
    m_product->quality = a_quality;
    m_product->brandLoyalty = a_brandLoyalty;
    m_product->brandAwareness = a_brandAwareness;
    m_product->sellPrice = a_sellPrice;
    m_product->purchasePrice = a_purchasePrice;
    m_product->freightCost = a_freightCost;
    m_product->totalCost = a_totalCost;
    m_product->marketShare = a_marketShare;
    m_product->productDemand = a_productDemand;
    m_product->rating = a_rating;
    m_product->cityAverageRating = a_cityAverageRating;

	// get values from Items database
    foreach(Item i, m_itemList)
    {
        if (i.productType == m_product->productType)
        {
            m_product->qualityConcern = i.qualityConcern;
            m_product->brandConcern = i.brandConcern;
            m_product->priceConcern = i.priceConcern;
            m_product->basePrice = i.basePrice;
            m_product->necessity = i.necessity;
            break;
        }
    }
	
    m_productIdCounter++;
    m_productMap.insert(a_productType, m_product);

    // Find productType in the list, if found, exit immediately.
    // No need to append same product type.
    for (int i = 0; i < m_productTypeList.size(); ++i) 
    {
        if (m_productTypeList.at(i) == a_productType)
        {
            return;
        }
    }
    m_productTypeList.append(a_productType);
}

bool ProductSimulation::DeleteProduct( quint32 a_productId )
{
    foreach(Product * i, m_productMap)
    {
        if (i->productId == a_productId)
        {
            quint16 key = i->productType; // map's key = productType
            delete i;
            m_productMap.remove(key,i);
            return true;
        }
    }
    return false;
}

void ProductSimulation::CalculateSales(City* a_city)
{
   // CalculateProductDemands();

    quint64 a_saleQuantity = 0;
    quint32 totalRating = 0;
    m_city = a_city;
    
    quint16 lastKey = -1;
    // iteration for each product type
    for (int i = 0; i < m_productTypeList.size(); ++i)
    {
        quint16 key = m_productTypeList.at(i);
        if (lastKey != key  || lastKey == -1)
        {
            //iteration for each product with the same type
            foreach(Product* it, m_productMap)
            {
                if (it->productType == key)
                {
                    it->rating = CalculateProductRating(it);
                    totalRating += it->rating;
                }
            }

            //iteration for each product with the same type
            foreach(Product* it, m_productMap)
            {
                if (it->productType == key)
                {
                     float demand;
                    demand = static_cast<double>(it->rating) / (totalRating) * 100;
                    it->productDemand = demand;
                    // this is placeholder for sales formula
                    a_saleQuantity = (m_city->population * static_cast<double>(it->productDemand * it->necessity * m_city->economyLevel * m_city->spendingLevel) / 10000000.00);
					int fivePercent = a_saleQuantity * 5 / 100;
					int randomNumber = Random(-fivePercent,fivePercent);
                    a_saleQuantity +=  randomNumber; // make counts nicer with random plus/minus
                    it->saleQuantity = a_saleQuantity;
                }
            }
            lastKey = key;
        }
    }

}

qint8 ProductSimulation::CalculateProductRating(Product* a_product)
{
    qint8 productRating = 0;

    productRating = (a_product->quality * a_product->qualityConcern) / 100 + 
					((a_product->brandAwareness + a_product->brandLoyalty) * a_product->brandConcern) / 100 +
					((a_product->sellPrice - a_product->basePrice ) / a_product->basePrice) * a_product->priceConcern / 100;

    return productRating;
}

quint8 ProductSimulation::CalculateCityAverageRating()
{
    return 0;
}

bool ProductSimulation::ParseItemsFromFile()
{
    const int itemColumn = 11;
    int counter = 0;
    QFile file(g_Setting->ResourcePath + "item.txt");
    if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
    {
        QMessageBox msgbox;
        msgbox.setText("Can't open item.txt");
        msgbox.exec();
        qCritical("Can't open item.txt");
        return false;
    }

    qDebug() << file.readLine();

    while (!file.atEnd()) 
    {
        Item a_item;
        QByteArray line = file.readLine();
        QString sLine = QString::fromLocal8Bit(line.data());
        QStringList sList = sLine.split("|");

        if (sList.size() == itemColumn) // make sure right column size
        {
            a_item.productClass = GetProductClassEnum(sList.at(0).trimmed());
            a_item.productType =  GetProductTypeEnum(sList.at(1).trimmed());
            a_item.productName =  sList.at(2).trimmed();
            a_item.basePrice =  sList.at(3).toUInt();
            a_item.freight =  sList.at(4).toUInt();
            a_item.demand =  sList.at(5).toUShort();
            a_item.luxuryLevel =  sList.at(6).toUShort();
            a_item.necessity =  sList.at(7).toUShort();
            a_item.priceConcern =  sList.at(8).toUShort();
            a_item.qualityConcern =  sList.at(9).toUShort();
            a_item.brandConcern =  sList.at(10).toUShort();
            m_itemList.append(a_item);
            counter++;
        }
    }
    qSort(m_itemList);
    return true;
}


